﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.IO;
using System.IO.Packaging;
using System.Text;

namespace OpenLS.Spreadsheet.Formats.Biff.OfficeArt
{
    internal class IMsoArray
    {
        private byte[] _data;
        private ushort cbElem;
        private ushort nElems;
        private ushort nElemsAlloc;

        public void Read(BinaryReader reader)
        {
            nElems = reader.ReadUInt16();
            nElemsAlloc = reader.ReadUInt16();
            cbElem = reader.ReadUInt16();
            int i = cbElem;
            if (i == 0xFFF0)
                i = 4;
            _data = reader.ReadBytes(i*nElems);
        }
    }
    enum LeftLineStyleBooleanProperties
    {
    fLeftNoLineDrawDash = 1,
    fLineLeftFillShape = 2,
    fLeftHitTestLine = 4,
    fLeftLine = 8,
    reserved1 = 16,
    fLeftInsetPenOK = 32,
    fLeftInsetPen = fLeftInsetPenOK*2,
    reserved2 = fLeftInsetPen*2,
    reserved3 = reserved2*2,
    unused1 = reserved3*2,
    unused21 = unused1*2,
    unused22 = unused21*2,
    unused23 = unused22*2,
    unused24 = unused23*2,
    unused25 = unused24*2,
    unused26 = unused25*2,
    fUsefLeftNoLineDrawDash = unused26*2,
    fUsefLineLeftFillShape = fUsefLeftNoLineDrawDash*2,
    fUsefLeftHitTestLine = fUsefLineLeftFillShape*2,
    fUsefLeftLine = fUsefLeftHitTestLine*2,
    unused3 = fUsefLeftLine*2,
    fUsefLeftInsetPenOK = unused3*2,
    fUsefLeftInsetPen = fUsefLeftInsetPenOK*2,
    unused4 = fUsefLeftInsetPen*2,
    unused5 = unused4*2,
    unused6 = unused5*2,
    }

    internal class OfficeArtFOPTE
    {
        private byte[] _data;
        private int _op;
        private OfficeArtFOPTEOPID _opid;

        public OfficeArtFOPTE(OpId propertyId, object value)
        {
            Contract.Requires(value != null || propertyId != OpId.MetroBlob);
            bool isComplex = false;
            if (value is string)
            {
                var str = (string) value;
                Contract.Assert(str.IndexOf('\0') == -1);
                _op = (str.Length + 1)*2;
                var chars = new char[str.Length + 1];
                for (int i = 0; i < str.Length; i++)
                    chars[i] = str[i];
                //terminal zero!
                _data = Encoding.Unicode.GetBytes(chars);
                Contract.Assert(_data.Length == _op);
                isComplex = true;
            }
            else if (value is byte[])
            {
                isComplex = true;
                _data = (byte[]) value;
                _op = _data.Length;
            }
            else
            {
                _op = ConvertFromObject(value);
            }
            _opid = new OfficeArtFOPTEOPID(propertyId, isComplex);
        }

        public OfficeArtFOPTE()
        {
        }

        internal OpId OpId
        {
            get { return _opid.Opid; }
        }

        public int ByteLength
        {
            get
            {
                int result = OfficeArtFOPTEOPID.ByteLength + 4;
                if (_data != null)
                    result += _data.Length;
                return result;
            }
        }

        internal object GetValue()
        {
            switch (_opid.Opid)
            {
                case OpId.LTxid:
                case OpId.DxTextLeft:
                case OpId.DxTextRight:
                case OpId.DyTextBottom:
                case OpId.DyTextTop:
                case OpId.LineOpacity:
                case OpId.FillWidth:
                case OpId.LineBottomFillWidth:
                case OpId.LineFillWidth:
                case OpId.LineLeftFillWidth:
                case OpId.LineRightFillWidth:
                case OpId.LineTopFillWidth:
                case OpId.FillHeight:
                case OpId.LineBottomFillHeight:
                case OpId.LineFillHeight:
                case OpId.LineLeftFillHeight:
                case OpId.LineRightFillHeight:
                case OpId.LineTopFillHeight:
                case OpId.FillFocus:
                case OpId.FillShadePreset:
                case OpId.ShadowOffsetX:
                case OpId.ShadowSecondOffsetX:
                case OpId.ShadowSecondOffsetY:
                case OpId.ShadowOffsetY:
                case OpId.C3DSkewAmount:
                case OpId.DxyCalloutDropSpecified:
                case OpId.DxyCalloutLengthSpecified:
                case OpId.DxWrapDistLeft:
                case OpId.DxWrapDistRight:
                case OpId.DyWrapDistBottom:
                case OpId.DyWrapDistTop:
                case OpId.PictureId:

                    return GetIntValue();
                case OpId.Txdir:
                    return GetEnumValue<MSOTXDIR>();
                case OpId.TextBooleanProperties:
                    return GetEnumValue<TextBooleanProperties>();
                case OpId.Cxk:
                    return GetEnumValue<Msocxk>();

                case OpId.FillColor:
                case OpId.FillBackColor:
                case OpId.LineColor:
                case OpId.ShadowColor:
                case OpId.PictureDblCrMod:
                case OpId.PictureFillCrMod:
                case OpId.PictureLineCrMod:
                case OpId.LineBackColor:
                case OpId.ShadowHighlight:
                case OpId.C3DExtrusionColor:
                case OpId.C3DCrMod:
                case OpId.LineBottomCrMod:
                case OpId.LineLeftCrMod:
                case OpId.LineRightCrMod:
                case OpId.LineTopCrMod:
                    return GetColorValue();

                case OpId.ShadowStyleBooleanProperties:
                    return GetEnumValue<ShadowStyleBooleanProperties>();
                case OpId.GroupShapeBooleanProperties:
                    return GetUintEnumValue<GroupShapeBooleanProperties>();
                case OpId.TxflTextFlow:
                    return GetEnumValue<MSOTXFL>();
                case OpId.FillBlip:
                case OpId.LineFillBlip:
                case OpId.LineWidth:
                    return GetUIntValue();
                case OpId.Rotation:
                case OpId.FillOpacity:
                case OpId.FillBackOpacity:
                case OpId.FillAngle:
                case OpId.FillToLeft:
                case OpId.FillToBottom:
                case OpId.FillToRight:
                case OpId.FillToTop:
                case OpId.FillRectLeft:
                case OpId.FillRectBottom:
                case OpId.FillRectTop:
                case OpId.FillRectRight:
                case OpId.FillOriginX:
                case OpId.FillOriginY:
                case OpId.FillShapeOriginX:
                case OpId.FillShapeOriginY:
                case OpId.LineMiterLimit:
                case OpId.ShadowOpacity:
                case OpId.ShadowOriginX:
                case OpId.ShadowOriginY:
                case OpId.C3DSpecularAmt:
                case OpId.C3DDiffuseAmt:
                case OpId.C3DShininess:
                case OpId.C3DYRotationAngle:
                case OpId.C3DXRotationAngle:
                case OpId.C3DRotationAxisX:
                case OpId.C3DRotationAxisY:
                case OpId.C3DRotationAxisZ:
                case OpId.C3DRotationAngle:
                case OpId.C3DRotationCenterX:
                case OpId.C3DRotationCenterY:
                case OpId.C3DRotationCenterZ:
                case OpId.C3DTolerance:
                case OpId.C3DXViewpoint:
                case OpId.C3DYViewpoint:
                case OpId.C3DZViewpoint:
                case OpId.C3DOriginX:
                case OpId.C3DOriginY:
                case OpId.C3DSkewAngle:
                case OpId.C3DAmbientIntensity:
                case OpId.C3DKeyX:
                case OpId.C3DKeyY:
                case OpId.C3DKeyZ:
                case OpId.C3DKeyIntensity:
                case OpId.C3DFillX:
                case OpId.C3DFillY:
                case OpId.C3DFillZ:
                case OpId.C3DFillIntensity:
                    case OpId.CropFromTop:
                    case OpId.CropFromBottom:
                    case OpId.CropFromLeft:
                    case OpId.CropFromRight:

                    return new FixedPoint(GetIntValue());
                case OpId.ProtectionBooleanProperties:
                    return GetEnumValue<ProtectionBooleanProperties>();
                case OpId.WrapText:
                    return GetEnumValue<MSOWRAPMODE>();

                case OpId.Unused134:
                case OpId.Unused140:
                case OpId.Unused141:
                case OpId.Unused832:
                case OpId.Unused906:
                case OpId.C3DEdgeThickness:
                case OpId.C3DExtrudeForward:
                case OpId.C3DExtrudeBackward:
                case OpId.DxyCalloutGap:
                    return GetIntValue();
                case OpId.AnchorText:
                    return GetEnumValue<MSOANCHOR>();
                case OpId.CdirFont:
                    return GetEnumValue<MSOCDIR>();
                case OpId.HspNext:
                    return GetUIntValue();
                case OpId.GeoLeft:
                case OpId.GeoBottom:
                case OpId.GeoRight:
                case OpId.GeoTop:
                    return GetIntValue();
                case OpId.ShapePath:
                    return GetEnumValue<MSOSHAPEPATH>();
                case OpId.PVertices:
                case OpId.PSegmentInfo:
                case OpId.PConnectionSites:
                case OpId.PConnectionSitesDir:
                case OpId.PAdjustHandles:
                case OpId.PGuides:
                    return GetIntValue();
                case OpId.GeometryBooleanProperties:
                    return GetUintEnumValue<GeometryBooleanProperties>();
                case OpId.FillType:
                    return GetEnumValue<MSOFILLTYPE>();
                case OpId.FillStyleBooleanProperties:
                    return GetEnumValue<FillStyleBooleanProperties>();
                case OpId.LineType:
                    return GetEnumValue<MSOLINETYPE>();
                case OpId.LineJoinStyle:
                    return GetEnumValue<MSOLINEJOIN>();
                case OpId.BottomLineStyleBooleanProperties:
                    return GetEnumValue<BottomLineStyleBooleanProperties>();
                case OpId.BWMode:
                    return GetEnumValue<MSOBWMODE>();
                case OpId.ShapeBooleanProperties:
                    return GetEnumValue<ShapeBooleanProperties>();
                case OpId.WzName:
                    return GetStringValue();
                case OpId.LineStyleBooleanProperties:
                    return GetEnumValue<LineStyleBooleanProperties>();
                case OpId.LidRegroup:
                    return GetUIntValue();
                case OpId.FillCrMod:
                case OpId.LineCrMod:
                case OpId.ShadowCrMod:
                    return GetColorValue();
                case OpId.Pib:
                    return GetUIntValue();
                case OpId.BlipBooleanProperties:
                    return GetEnumValue<BlipBooleanProperties>();
                case OpId.PibName:
                case OpId.WzDescription:
                    return GetStringValue();
                case OpId.LineStyle:
                    return GetEnumValue<MSOLINESTYLE>();
                case OpId.MetroBlob:
                    {
                        var ms = new MemoryStream(_data);
                        {
                            Package package = Package.Open(ms);
                            return package;
                        }
                    }
                case OpId.FillBlipName:
                case OpId.LineFillBlipName:
                case OpId.LineBottomFillBlipName:
                case OpId.LineLeftFillBlipName:
                case OpId.LineRightFillBlipName:
                case OpId.LineTopFillBlipName:
                    return GetStringValue();
                case OpId.FillBlipFlags:
                case OpId.LineBottomFillBlipFlags:
                case OpId.LineFillBlipFlags:
                case OpId.LineLeftFillBlipFlags:
                case OpId.LineRightFillBlipFlags:
                case OpId.LineTopFillBlipFlags:
                    case OpId.PibFlags:
                    return GetEnumValue<MSOBLIPFLAGS>();
                case OpId.FillDztype:
                case OpId.LineBottomFillDztype:
                case OpId.LineFillDztype:
                case OpId.LineLeftFillDztype:
                case OpId.LineRightFillDztype:
                case OpId.LineTopFillDztype:
                    return GetEnumValue<MSODZTYPE>();
                case OpId.FillShadeColors:
                case OpId.PWrapPolygonVertices:
                    return GetMsoArrays();
                case OpId.FillShadeType:
                    return GetEnumValue<MSOSHADETYPE>();
                case OpId.LineDashing:
                    return GetEnumValue<MSOLINEDASHING>();
                case OpId.LineDashStyle:
                    return GetMsoArrays();
                case OpId.LineEndCapStyle:
                    return GetEnumValue<MSOLINECAP>();
                case OpId.ShadowType:
                    return GetEnumValue<MSOSHADOWTYPE>();
                case OpId.Invalid1:
                case OpId.Invalid2:
                case OpId.Invalid3:
                case OpId.Invalid4:
                case OpId.Invalid5:
                case OpId.Invalid6:
                case OpId.Invalid7:
                case OpId.Invalid8:
                case OpId.Reserved1370:
                case OpId.Reserved1372:
                case OpId.Reserved1374:
                case OpId.Reserved1376:
                case OpId.Reserved1377:
                case OpId.Reserved1378:
                case OpId.Reserved1434:
                case OpId.Reserved1436:
                case OpId.Reserved1438:
                case OpId.Reserved1440:
                case OpId.Reserved1441:
                case OpId.Reserved1442:
                case OpId.Reserved1498:
                case OpId.Reserved1500:
                case OpId.Reserved1502:
                case OpId.Reserved1504:
                case OpId.Reserved1505:
                case OpId.Reserved1506:
                case OpId.Reserved1562:
                case OpId.Reserved1564:
                case OpId.Reserved1566:
                case OpId.Reserved1568:
                case OpId.Reserved1569:
                case OpId.Reserved1570:
                case OpId.Reserved278:
                case OpId.Reserved280:
                case OpId.Reserved281:
                case OpId.Reserved284:
                case OpId.Reserved286:
                case OpId.Reserved287:
                case OpId.Reserved415:
                case OpId.Reserved417:
                case OpId.Reserved419:
                case OpId.Reserved422:
                case OpId.Reserved423:
                case OpId.Reserved474:
                case OpId.Reserved476:
                case OpId.Reserved478:
                case OpId.Reserved480:
                case OpId.Reserved481:
                case OpId.Reserved482:
                case OpId.Reserved531:
                case OpId.Reserved533:
                case OpId.Reserved535:
                case OpId.Reserved537:
                case OpId.Reserved538:
                case OpId.Reserved539:
                case OpId.Reserved646:
                case OpId.Reserved650:
                case OpId.Reserved652:
                case OpId.Reserved653:
                    return GetIntValue();
                case OpId.ThreeDObjectBooleanProperties:
                    return GetEnumValue<ThreeDObjectBooleanProperties>();
                case OpId.ThreeDStyleBooleanProperties:
                    return GetEnumValue<ThreeDStyleBooleanProperties>();
                case OpId.C3DRenderMode:
                    return GetEnumValue<MSO3DRENDERMODE>();
                case OpId.Spcoa:
                    return GetEnumValue<Spcoa>();
                case OpId.Spcod:
                    return GetEnumValue<Spcod>();
                case OpId.CalloutBooleanProperties:
                    return GetEnumValue<CalloutBooleanProperties>();
                    case OpId.Posh:
                    return GetEnumValue<Posh>();
                    case OpId.Posrelh:
                    return GetEnumValue<Posrelh>();
                case OpId.Posv:
                    return GetEnumValue<Posv>();
                case OpId.Posrelv:
                    return GetEnumValue<Posrelv>();
                case OfficeArt.OpId.LeftLineStyleBooleanProperties:
                    return GetEnumValue<LeftLineStyleBooleanProperties>();
                    case OpId.TopLineStyleBooleanProperties:
                    return GetEnumValue<TopLineStyleBooleanProperties>();
                    case OpId.RightLineStyleBooleanProperties:
                    return GetEnumValue<RightLineStyleBooleanProperties>();
                    case OpId.PictureBrightness:
                    return GetIntValue();
                    default:
                    {
                        Debug.WriteLine("Unhandled" + OpId);
                        Contract.Assert(false, OpId.ToString());
                        return null;
                    }
            }
        }


        private List<IMsoArray> GetMsoArrays()
        {
            int totalBytes = _data.Length;
            var reader = new BinaryReader(new MemoryStream(_data));
            var result = new List<IMsoArray>();
            while (reader.BaseStream.Position < totalBytes)
            {
                var item = new IMsoArray();
                item.Read(reader);
                result.Add(item);
            }
            return result;
        }

        private uint GetUIntValue()
        {
            return (uint) _op;
        }

        private OfficeArtCOLORREF GetColorValue
            ()
        {
            return new OfficeArtCOLORREF(GetIntValue());
        }


        private T GetEnumValue<T>() where T : struct
        {
            Contract.Assert(typeof (Enum).IsAssignableFrom(typeof (T)));
            return (T) (object) GetIntValue();
        }

        private T GetUintEnumValue<T>() where T : struct
        {
            Contract.Assert(typeof (Enum).IsAssignableFrom(typeof (T)));
            return (T) (object) (uint) GetIntValue();
        }


        internal int GetIntValue()
        {
            return _op;
        }

        public void Read(BinaryReader reader)
        {
            _opid = new OfficeArtFOPTEOPID();
            _opid.Read(reader);
            _op = reader.ReadInt32();
        }


        private int ConvertFromObject(object value)
        {
            if (value is Enum)
            {
                return Convert.ToInt32(value);
            }
            if (value is int)
                return (int) value;
            if (value is uint)
                return (int) value;
            if (value is OfficeArtCOLORREF)
            {
                var c = (OfficeArtCOLORREF) value;
                return c.ToInt();
            }
            throw new NotSupportedException();
        }

        public void Write(BinaryWriter writer)
        {
            _opid.Write(writer);
            writer.Write(_op);
        }

        public void ReadComplexPart(BinaryReader reader)
        {
            if (_opid.fComplex)
                _data = reader.ReadBytes(_op);
#if DEBUG
            GetValue();
            //\\ Debug.WriteLine("Reading " + this.OpId + " " + _value);
#endif
        }

        public void WriteComplexPart(BinaryWriter writer)
        {
            if (_opid.fComplex)
                writer.Write(_data);
        }

        public string GetStringValue()
        {
            Contract.Assert(_opid.fComplex);
            return (string) new ComplexString(_data);
        }
    }

    internal enum RightLineStyleBooleanProperties
    {
        fRightNoLineDrawDash = 1,
        fLineRightFillShape = fRightNoLineDrawDash*2,
        fRightHitTestLine = fLineRightFillShape*2,
    fRightLine = fRightHitTestLine*2,
    reserved1 = fRightLine*2,
    fRightInsetPenOK = reserved1*2,
    fRightInsetPen = fRightInsetPenOK*2,
    reserved2 = fRightInsetPen*2,
    reserved3 = reserved2*2,
    unused1 = reserved3*2,
    unused21 = unused1*2,
    unused22 = unused21*2,
    unused23 = unused22*2,
    unused24 = unused23*2,
    unused25 = unused24*2,
    unused26 = unused25*2,
    fUsefRightNoLineDrawDash = unused26*2,
    fUsefLineRightFillShape = fUsefRightNoLineDrawDash*2,
    fUsefRightHitTestLine = fUsefLineRightFillShape*2,
    fUsefRightLine = fUsefRightHitTestLine*2,
    unused3 = fUsefRightLine*2,
    fUsefRightInsetPenOK = unused3*2,
    fUsefRightInsetPen = fUsefRightInsetPenOK*2,
    unused4 = fUsefRightInsetPen*2,
    unused5 = unused4*2,
    unused6 = unused5*2,

    }

    internal enum TopLineStyleBooleanProperties
    {
        fTopNoLineDrawDash = 1,
        fLineTopFillShape    = fTopNoLineDrawDash*2,
        fTopHitTestLine = fLineTopFillShape   *2,
        fTopLine = fTopHitTestLine*2,
    reserved1 = fTopLine*2,
    fTopInsetPenOK = reserved1*2,
    fTopInsetPen = fTopInsetPenOK*2,
    reserved2 = fTopInsetPen*2,
    reserved3 = reserved2*2,
    unused1 = reserved3*2,
    unused21 = unused1*2,
    unused22 = unused21*2,
    unused23 = unused22*2,
    unused24 = unused23*2,
    unused25 = unused24*2,
    unused26 = unused25*2,
    fUsefTopNoLineDrawDash = unused26*2,
    fUsefLineTopFillShape = fUsefTopNoLineDrawDash*2,
    fUsefTopHitTestLine = fUsefLineTopFillShape*2,
    fUsefTopLine = fUsefTopHitTestLine*2,
    unused3 = fUsefTopLine*2,
    fUsefTopInsetPenOK = unused3*2,
    fUsefTopInsetPen = fUsefTopInsetPenOK*2,
    unused4 = fUsefTopInsetPen*2,
    unused5 = unused4*2,
    unused6 = unused5*2,
    }

    internal enum Posrelv
    {
        msoprvMargin = 0x001,
        msoprvPage = 0x002,
        msoprvText = 0x003,
        msoprvLine = 0x004,
    }

    internal enum Posv
    {
msopvAbs = 0x00000000,
//The shape is vertically offset by an absolute distance from the page element.
msopvTop = 0x00000001,
//The shape is vertically positioned at the top of the page element.
msopvCenter = 0x00000002,
//The shape is vertically positioned in the center of the page element.
msopvBottom = 0x00000003,
//The shape is vertically positioned at the bottom of the page element.
msopvInside = 0x00000004,
//The shape is vertically positioned like msopvTop on odd-numbered pages and like msopvBottom on even-numbered pages.
msopvOutside = 0x00000005,
//The shape is vertically positioned like msopvBottom on odd-numbered pages and like msopvTop on even-numbered pages.
    }

    internal enum Posrelh
    {
msoprhMargin = 0x00000001,
//The shape is horizontally positioned relative to the margins of the page:
msoprhPage = 0x00000002,
//The shape is horizontally positioned relative to the edges of the page:
msoprhText = 0x00000003,
//The shape is horizontally positioned relative to the column of text underneath it:
msoprhChar = 0x00000004,
//The shape is horizontally positioned relative to the character of text underneath it:
//msoprhMargin = 0x00000001,
//The shape is horizontally positioned relative to the margins of the page:
//msoprhPage = 0x00000002,
//The shape is horizontally positioned relative to the edges of the page:
//msoprhText = 0x00000003,
//The shape is horizontally positioned relative to the column of text underneath it:
//msoprhChar = 0x00000004,
//The shape is horizontally positioned relative to the character of text underneath it:
//msoprhMargin = 0x00000001,
//The shape is horizontally positioned relative to the margins of the page:
//msoprhPage = 0x00000002,
//The shape is horizontally positioned relative to the edges of the page:
//msoprhText = 0x00000003,
//The shape is horizontally positioned relative to the column of text underneath it:
//msoprhChar = 0x00000004,
//The shape is horizontally positioned relative to the character of text underneath it:
//msoprhMargin = 0x00000001,
//The shape is horizontally positioned relative to the margins of the page:
//msoprhPage = 0x00000002,
//The shape is horizontally positioned relative to the edges of the page:
//msoprhText = 0x00000003,
//The shape is horizontally positioned relative to the column of text underneath it:
//msoprhChar = 0x00000004,
//The shape is horizontally positioned relative to the character of text underneath it:
//msoprhMargin = 0x00000001,
//The shape is horizontally positioned relative to the margins of the page.
//msoprhPage = 0x00000002,
//The shape is horizontally positioned relative to the edges of the page.
//msoprhText = 0x00000003,
//The shape is horizontally positioned relative to the column of text underneath it.
//msoprhChar = 0x00000004,
//The shape is horizontally positioned relative to the character of text underneath it.
//msoprhMargin = 0x00000001,
//The shape is horizontally positioned relative to the margins of the page.
//msoprhPage = 0x00000002,
//The shape is horizontally positioned relative to the edges of the page.
//msoprhText = 0x00000003,
//The shape is horizontally positioned relative to the column of text underneath it.

    }

    internal enum Posh
    {
msophAbs = 0x00000000,
//The shape is horizontally offset by an absolute distance from the page element.
msophLeft = 0x00000001,
//The shape is horizontally positioned at the left side of the page element.
msophCenter = 0x00000002,
//The shape is horizontally positioned at the center of the page element.
msophRight = 0x00000003,
//The shape is horizontally positioned at the right side of the page element.
msophInside = 0x00000004,
//The shape is horizontally positioned like msophLeft on odd-numbered pages and like msophRight on even-numbered pages.
msophOutside = 0x00000005,
//The shape is horizontally positioned like msophRight on odd-numbered pages and like msophLeft on even-numbered pages.
    }

    internal enum CalloutBooleanProperties
    {
        fCalloutLengthSpecified = 0x00000001,
        fCalloutDropAuto = 0x00000002,
        fCalloutMinusY = 0x00000004,
        fCalloutMinusX = 0x00000008,
        fCalloutTextBorder = 0x00000010,
        fCalloutAccentBar = 0x00000020,
        fCallout = 0x00000040,
        fUsefCalloutLengthSpecified = 0x00000010000,
        fUsefCalloutDropAuto = 0x00000020000,
        fUsefCalloutMinusY = 0x00000040000,
        fUsefCalloutMinusX = 0x000000100000,
        fUsefCalloutTextBorder = 0x000000200000,
        fUsefCalloutAccentBar = 0x000000400000,
        fUsefCallout = 0x000000800000,
    }

    internal enum Spcod
    {
        msospcodTop = 0x00000000,
//This callout connects to the top of the callout box.
        msospcodCenter = 0x00000001,
//This callout connects to the callout box at the midpoint of its top and bottom coordinates.
        msospcodBottom = 0x00000002,
//This callout connects to the bottom of the callout box.
        msospcodSpecified = 0x00000003,
//This callout connects to the callout box as defined by the dxyCalloutDropSpecified property, as defined in section 2.3.3.5.
    }

    internal enum Spcoa
    {
        msospcoaAny = 0x00000000,
//The callout is drawn according to its list of vertices.
        msospcoa30 = 0x00000001,
//The callout is drawn at a 30-degree angle.
        msospcoa45 = 0x00000002,
//The callout is drawn at a 45-degree angle.
        msospcoa60 = 0x00000003,
//The callout is drawn at a 60-degree angle.
        msospcoa90 = 0x00000004,
//The callout is drawn vertically.
        msospcoa0 = 0x00000005,
//The callout is drawn horizontally.
    }

    internal enum ThreeDStyleBooleanProperties
    {
        fc3DFillHarsh = 1,
        fc3DKeyHarsh = 0x2,
        fc3DParallel = 0x00004,
        fc3DRotationCenterAuto = 0x00008,
        fc3DConstrainRotation = 0x00010,
        fUsefc3DFillHarsh = 0x0010000,
        fUsefc3DKeyHarsh = 0x0020000,
        fUsefc3DParallel = 0x0040000,
        fUsefc3DRotationCenterAuto = 0x0080000,
        fUsefc3DConstrainRotation = 0x00100000,
    }

    internal enum MSOSHADETYPE
    {
        msoshadeNone = 1,
        // (1 bit): A bit that specifies whether color correction will be performed after interpolation. A value of 0x1 specifies that no color correction will be performed after interpolation.
        msoshadeGamma = 0x2,
        //(1 bit): A bit that specifies whether gamma correction will be applied after interpolation.
        msoshadeSigma = 0x4,
        // (1 bit): A bit that specifies whether a sigma transfer function will be applied after interpolation.
        msoshadeBand = 0x8,
        // (1 bit): A bit that specifies whether a flat band will be added at the start of the interpolation.
        msoshadeOneColor = 0x10,
        // (1 bit): A bit that specifies whether only one color will be used for the fill color.
    }
}